// test_stdcallthunk.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <atlstdthunk.h>
#include <vector>

using namespace std;

class TimerObjBase
{
public:
	class ITimerObjBaseEvent
	{
	public:
		virtual void DoTimer(DWORD dwID, DWORD dwSlap, LPVOID lParam) = 0;
	};

	struct TimerStruct
	{
		UINT_PTR dwTimerID;//TimerID
		DWORD dwEventID;//User defined ID
		UINT nSlap;
		CStdCallThunk thunk;
		void* pEvent;
		LPVOID lParam;

		TimerStruct()
		{
			dwTimerID = dwEventID = nSlap = 0;
			pEvent = lParam = NULL;
		}
	};

	void SetNewTimer(UINT_PTR  dwEventID, UINT dwSlap, ITimerObjBaseEvent* pEvent, LPVOID lParam)
	{
		if (m_vectTimer.size() != 0)
		{
			TimerInfoContainer::iterator it = m_vectTimer.begin();
			for (; it != m_vectTimer.end(); ++it)
			{
				TimerStruct* p = *it;
				if (p && p->dwEventID == dwEventID)
				{
					//reset
					p->nSlap = dwSlap;
					p->lParam = lParam;
					p->pEvent = pEvent;
					p->dwTimerID = ::SetTimer(NULL, p->dwTimerID, dwSlap, (TIMERPROC)(p->thunk.GetCodeAddress()));
					return;
				}
			}
		}
		
		//add new
		TimerStruct* p = new TimerStruct();
		if (p)
		{
			p->thunk.Init((DWORD_PTR)TimerObjBase::TimerProc, p);
			p->pEvent = pEvent;
			p->lParam = lParam;
			p->nSlap = dwSlap;
			p->dwEventID = dwEventID;
			p->dwTimerID = ::SetTimer(NULL, 0, dwSlap, (TIMERPROC)(p->thunk.GetCodeAddress()));
		
			m_vectTimer.push_back(p);
		}
	}

	void RemoveTimer(UINT_PTR dwEventID)
	{
		TimerInfoContainer::iterator it = m_vectTimer.begin();
		for (; it != m_vectTimer.end(); ++it)
		{
			TimerStruct* p = *it;
			if (p && p->dwEventID == dwEventID)
			{
				::KillTimer(NULL, p->dwTimerID);
				m_vectTimer.erase(it);
				delete p;
				break;
			}
		}
	}

	static void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT_PTR  idEvent, DWORD dwTime)
	{
		TimerStruct* p = (TimerStruct*)hWnd;
		if (p)
		{
			ITimerObjBaseEvent* pBase = (ITimerObjBaseEvent*)p->pEvent;
			if (pBase)
			{
				pBase->DoTimer(p->dwEventID, p->dwTimerID, p->lParam);
			}
		}
	}
	
private:
	typedef std::vector<TimerStruct*> TimerInfoContainer;
	TimerInfoContainer m_vectTimer;
};

class ATimer : public TimerObjBase::ITimerObjBaseEvent
{
public:
	virtual void DoTimer(DWORD dwID, DWORD dwSlap, LPVOID lParam)
	{
		if (dwID == 1)
		{
			static int n = 5;
			if (n >= 3)
			{
				cout << "1 second timer pass" <<endl;
			}
			else
			{
				cout << "2 second timer pass" <<endl;
			}

			n--;
			if (n == 2)
			{
				m_timer.SetNewTimer(1, 2000, this, NULL);
			}
			else if (n == -1)
			{
				m_timer.RemoveTimer(1);
				m_timer.SetNewTimer(2, 1000, this, NULL);
			}
		}
		else if (dwID == 2)
		{
			static int k = 2;
			cout << "event 2 timer hit" <<endl;
			k--;
			if (k == -1)
			{
				m_timer.RemoveTimer(2);
			}
		}
	}

	void Start()
	{
		m_timer.SetNewTimer(1, 1000, this, NULL);
	}

	TimerObjBase m_timer;
};


int _tmain(int argc, _TCHAR* argv[])
{
	DWORD dwID = 1;
	ATimer obj;
	obj.Start();

	MSG msg;
	while (GetMessage(&msg, 0, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return 0;
}

